package vip.xiaonuo.core.util;

import cn.hutool.core.lang.Snowflake;
import okhttp3.*;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * OkHttpUtil.
 *
 * @author: yang.kui
 * @email: yang.kui@mangocosmos.com
 * @create: 2021-04-02 18:33
 **/
public class HttpUtil {

    private static final Logger log = LoggerFactory.getLogger(HttpUtil.class);

    //空闲连接数
    private static final int MAX_IDLE_CONNECTIONS = 30;
    //保持连接时间
    private static final long KEEP_ALLIVE_TIME = 60000L;
    //连接超时时间
    public static final int CONN_TIME_OUT_SECONDS = 6;
    //读超时时间
    public static final int READ_TIME_OUT_SECONDS = 9;
    //写超时时间
    public static final int WRITE_TIME_OUT_SECONDS = 9;

    private OkHttpClient okHttpClient;

    private volatile static HttpUtil httpUtils;

    public static HttpUtil getInstance() {
        if (Objects.isNull(httpUtils)) {
            synchronized (HttpUtil.class) {
                if (Objects.isNull(httpUtils)) {
                    httpUtils = new HttpUtil();
                }
            }
        }
        return httpUtils;
    }

    public HttpUtil() {
        ConnectionPool connectionPool = new ConnectionPool(MAX_IDLE_CONNECTIONS, KEEP_ALLIVE_TIME, TimeUnit.MILLISECONDS);
        this.okHttpClient = new OkHttpClient().newBuilder().readTimeout(READ_TIME_OUT_SECONDS, TimeUnit.SECONDS).writeTimeout(WRITE_TIME_OUT_SECONDS, TimeUnit.SECONDS).connectTimeout(CONN_TIME_OUT_SECONDS, TimeUnit.SECONDS).connectionPool(connectionPool)
                //自动重连设置为false
                .retryOnConnectionFailure(false)
                //重试拦截器2次
                //.addInterceptor(new RetryIntercepter(2))
                //网络拦截器，统一打印日志
                .addNetworkInterceptor(new OkHttpInterceptor()).build();
    }


    /**
     * 根据map获取get请求参数
     *
     * @param url
     * @param queryStringParams
     * @return
     */
    public HttpUrl getQueryString(String url, Map<String, Object> queryStringParams) {
        HttpUrl.Builder httpUrlBuilder = Objects.requireNonNull(HttpUrl.parse(url)).newBuilder();
        if (MapUtils.isNotEmpty(queryStringParams)) {
            queryStringParams.forEach((key, val) -> {
                httpUrlBuilder.addQueryParameter(key, Objects.nonNull(val) ? val.toString() : StringUtils.EMPTY);
            });
        }
        return httpUrlBuilder.build();
    }

    public FormBody getFormBody(Map<String, Object> params) {
        FormBody.Builder builder = new FormBody.Builder();
        //添加参数
        if (MapUtils.isNotEmpty(params)) {
            params.forEach((key, val) -> {
                builder.add(key, Objects.nonNull(val) ? val.toString() : StringUtils.EMPTY);
            });
        }
        return builder.build();
    }

    /**
     * 提交文件表单
     *
     * @param params
     * @param files
     * @param fileKey
     * @return
     */
    public MultipartBody getMultipartBody(Map<String, Object> params, List<File> files, String fileKey) {
        MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
        if (MapUtils.isNotEmpty(params)) {
            params.forEach((key, val) -> {
                if (Objects.nonNull(val)) {
                    builder.addFormDataPart(key, val.toString());
                }
            });
        }
        if (CollectionUtils.isNotEmpty(files)) {
            files.forEach(file -> builder.addFormDataPart(fileKey, new Snowflake(0, 0).nextIdStr().concat(".jpg"), RequestBody.create(MediaType.parse("image/jpeg"), file)));
        }
        return builder.build();
    }

    /**
     * 调用okhttp的newCall方法
     *
     * @param request
     * @return
     */
    public Response execute(Request request) {
        try {
            return getInstance().okHttpClient.newCall(request).execute();
        } catch (IOException e) {
            log.error("发送请求发生错误：{}", ExceptionUtils.getStackTrace(e));
            return null;
        }
    }

    /**
     * get
     *
     * @param url               请求的url
     * @param queryStringParams 请求的参数
     * @return
     */
    public String get(String url, Map<String, Object> queryStringParams) {
        Request request = new Request.Builder().url(getQueryString(url, queryStringParams)).build();
        Response response = execute(request);
        if (Objects.nonNull(response) && response.isSuccessful()) {
            return response.body().toString();
        }
        return StringUtils.EMPTY;
    }

    /**
     * postMultipartFormData
     *
     * @param url
     * @param params
     * @param fileList
     * @param fileKey
     * @return
     */
    public Response postMultipartFormData(String url, Map<String, Object> params, List<File> fileList, String fileKey) {
        MultipartBody multipartBody = getMultipartBody(params, fileList, fileKey);
        Request request = new Request.Builder().url(url).post(multipartBody).build();
        return execute(request);
    }

    /**
     * post
     *
     * @param url    请求的url
     * @param params post form 提交的参数
     * @return
     */
    public String postFormParams(String url, Map<String, Object> params) {
        Request request = new Request.Builder().url(url).post(getFormBody(params)).build();
        Response response = execute(request);
        if (Objects.nonNull(response) && response.isSuccessful()) {
            return response.body().toString();
        }
        return StringUtils.EMPTY;
    }


    /**
     * Post请求发送JSON数据
     *
     * @param url
     * @param jsonParams
     * @return
     */
    public String postJsonParams(String url, String jsonParams) {
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), jsonParams);
        Request request = new Request.Builder().url(url).post(requestBody).build();
        Response response = execute(request);
        if (Objects.nonNull(response) && response.isSuccessful()) {
            return response.body().toString();
        }
        return StringUtils.EMPTY;
    }


    /**
     * Post请求发送xml数据
     *
     * @param url
     * @param xml
     * @return
     */
    public String postXmlParams(String url, String xml) {
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/xml; charset=utf-8"), xml);
        Request request = new Request.Builder().url(url).post(requestBody).build();
        Response response = execute(request);
        if (Objects.nonNull(response) && response.isSuccessful()) {
            return response.body().toString();
        }
        return StringUtils.EMPTY;
    }

}
